package log

import (
	"errors"
	"fmt"
	"golang.org/x/sys/windows/svc/eventlog"
	"os"
	"runtime/debug"
	"sync"
	"time"
)

// LogLevel 日志级别类型
type LogLevel int

const (
	FATAL LogLevel = iota
	CRITICAL
	ERROR
	WARNING
	NOTICE
	INFO
	DEBUG
)

const TimeFormat = "2006-01-02 15:04:05"

// 全局配置
var (
	globalLogLevel  LogLevel = DEBUG
	printStackTrace bool     = false
	winEventLog     *eventlog.Log
	fileLogger      *os.File
	fileMutex       sync.Mutex
	maxLogSize      int64 = 100 * 1024 * 1024 // 100MB
	maxBackupCount  int   = 3
)

// 初始化Windows事件日志（使用内置Application事件源）
func init() {
	el, err := eventlog.Open("Application")
	if err == nil {
		winEventLog = el
	}
}

// 日志级别转字符串
func (l LogLevel) String() string {
	switch l {
	case FATAL:
		return "FATAL"
	case CRITICAL:
		return "CRITICAL"
	case ERROR:
		return "ERROR"
	case WARNING:
		return "WARNING"
	case NOTICE:
		return "NOTICE"
	case INFO:
		return "INFO"
	case DEBUG:
		return "DEBUG"
	}
	return "unknown"
}

// 映射日志级别到Windows事件类型和事件ID
func mapLevelToEvent(logLevel LogLevel) (eventType uint16, eventID uint32) {
	switch logLevel {
	case FATAL, CRITICAL:
		return eventlog.Error, 1000
	case ERROR:
		return eventlog.Error, 1001
	case WARNING:
		return eventlog.Warning, 1002
	default: // NOTICE, INFO, DEBUG
		return eventlog.Info, 1003
	}
}

// 启用文件日志
func EnableFileLogging(filePath string) error {
	fileMutex.Lock()
	defer fileMutex.Unlock()

	if fileLogger != nil {
		fileLogger.Close()
	}

	f, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return err
	}

	fileLogger = f
	return nil
}

// 检查并执行日志轮转
func checkLogRotation() {
	if fileLogger == nil {
		return
	}

	fileMutex.Lock()
	defer fileMutex.Unlock()

	info, err := fileLogger.Stat()
	if err != nil {
		return
	}

	if info.Size() < maxLogSize {
		return
	}

	// 执行轮转
	currentPath := fileLogger.Name()
	fileLogger.Close()

	for i := maxBackupCount - 1; i > 0; i-- {
		oldName := fmt.Sprintf("%s.%d", currentPath, i)
		newName := fmt.Sprintf("%s.%d", currentPath, i+1)
		os.Rename(oldName, newName)
	}

	os.Rename(currentPath, fmt.Sprintf("%s.1", currentPath))

	f, err := os.OpenFile(currentPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		fileLogger = nil
		fmt.Fprintf(os.Stderr, "Failed to rotate log file: %v\n", err)
		return
	}

	fileLogger = f
}

// 写入Windows事件日志
func logToWindowsEvent(logLevel LogLevel, message string) {
	if winEventLog == nil || logLevel > globalLogLevel {
		return
	}

	eventType, eventID := mapLevelToEvent(logLevel)
	switch eventType {
	case eventlog.Error:
		winEventLog.Error(eventID, message)
	case eventlog.Warning:
		winEventLog.Warning(eventID, message)
	case eventlog.Info:
		winEventLog.Info(eventID, message)
	}
}

// 核心日志记录函数
func logFormattedEntry(logLevel LogLevel, message string, args ...interface{}) string {
	if logLevel > globalLogLevel {
		return ""
	}

	checkLogRotation()

	msgArgs := fmt.Sprintf(message, args...)
	localizedTime := getLocalizedTime()
	entryString := fmt.Sprintf("%s %s %s", localizedTime.Format(TimeFormat), logLevel, msgArgs)

	// 输出到标准错误
	fmt.Fprintln(os.Stderr, entryString)

	// 输出到文件
	if fileLogger != nil {
		fileMutex.Lock()
		fmt.Fprintln(fileLogger, entryString)
		fileMutex.Unlock()
	}

	// 写入Windows事件日志
	logToWindowsEvent(logLevel, msgArgs)

	return entryString
}

// 获取本地化时间
func getLocalizedTime() time.Time {
	localizedTime := time.Now()
	tzLocation := os.Getenv("TZ")
	if tzLocation != "" {
		location, err := time.LoadLocation(tzLocation)
		if err == nil {
			localizedTime = time.Now().In(location)
		}
	}
	return localizedTime
}

// 错误日志专用函数
func logErrorEntry(logLevel LogLevel, err error) error {
	if err == nil {
		return nil
	}

	entryString := fmt.Sprintf("%+v", err)
	logFormattedEntry(logLevel, entryString)

	if printStackTrace {
		debug.PrintStack()
	}

	return err
}

// 公共API函数
func SetPrintStackTrace(shouldPrint bool) {
	printStackTrace = shouldPrint
}

func SetLevel(logLevel LogLevel) {
	globalLogLevel = logLevel
}

func GetLevel() LogLevel {
	return globalLogLevel
}

func SetMaxLogSize(sizeMB int64) {
	maxLogSize = sizeMB * 1024 * 1024
}

// 各级别日志函数
func Debug(message string, args ...interface{}) string {
	return logFormattedEntry(DEBUG, message, args...)
}

func Debugf(message string, args ...interface{}) string {
	return logFormattedEntry(DEBUG, message, args...)
}

func Info(message string, args ...interface{}) string {
	return logFormattedEntry(INFO, message, args...)
}

func Infof(message string, args ...interface{}) string {
	return logFormattedEntry(INFO, message, args...)
}

func Notice(message string, args ...interface{}) string {
	return logFormattedEntry(NOTICE, message, args...)
}

func Noticef(message string, args ...interface{}) string {
	return logFormattedEntry(NOTICE, message, args...)
}

func Warning(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(WARNING, message, args...))
}

func Warningf(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(WARNING, message, args...))
}

func Error(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(ERROR, message, args...))
}

func Errorf(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(ERROR, message, args...))
}

func Errore(err error) error {
	return logErrorEntry(ERROR, err)
}

func Critical(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(CRITICAL, message, args...))
}

func Criticalf(message string, args ...interface{}) error {
	return errors.New(logFormattedEntry(CRITICAL, message, args...))
}

func Criticale(err error) error {
	return logErrorEntry(CRITICAL, err)
}

func Fatal(message string, args ...interface{}) error {
	logFormattedEntry(FATAL, message, args...)
	os.Exit(1)
	return nil
}

func Fatalf(message string, args ...interface{}) error {
	logFormattedEntry(FATAL, message, args...)
	os.Exit(1)
	return nil
}

func Fatale(err error) error {
	logErrorEntry(FATAL, err)
	os.Exit(1)
	return err
}
